Skip to content

fix(drawer): keep open drawers on-screen in RTL - #43345

Open
ump45nose wants to merge 1 commit into
twbs:mainfrom
ump45nose:fix/43340-drawer-rtl-transform-specificity
Open

ump45nose wants to merge 1 commit into
twbs:mainfrom
ump45nose:fix/43340-drawer-rtl-transform-specificity

Conversation

@ump45nose

Copy link
Copy Markdown
Contributor

Description

The default (animated) drawer uses an off-canvas translateX while closed, then [open] { transform: none } to slide it back on-screen. The RTL flip of that off-canvas transform was written as:

:root:dir(rtl) .drawer:not(.drawer-instant):where(.drawer-start) {
  transform: translateX(calc(100% + var(--bs-drawer-inset)));
}

That selector is more specific than .drawer:not(.drawer-instant)[open] { transform: none }, so in RTL the closed-state translation wins after open. The backdrop still appears (the <dialog> is in the top layer), but the panel stays outside the viewport.

This wraps the RTL qualifier in :where() so the off-canvas rule has the same specificity as the LTR equivalent and the open state can win. LTR start/end placement is unchanged.

Motivation & Context

Fixes #43340 (confirmed). A reduced case with dir="rtl" on <html> and a .drawer.drawer-start / .drawer-end opened via the open attribute shows the panel translated fully off-screen on current main CSS; after this change the computed transform is none and the panel sits on the correct inline side (start on the right, end on the left).

Type of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Refactoring (non-breaking change)
  • Breaking change (fix or feature that would change existing functionality)

Checklist

  • I have read the contributing guidelines
  • My code follows the code style of the project (using npm run lint)
  • My change introduces changes to the documentation
  • I have updated the documentation accordingly
  • I have added tests to cover my changes
  • All new and existing tests passed

scss/_drawer.scss was stylelint-clean. npm run css-compile and npm run css-prefix-main were run locally to inspect the compiled selectors; dist files are not included, per the contributing guidelines. There is no existing CSS cascade test fixture for drawer placement, so the open-state transform / getBoundingClientRect() behavior was verified in headless Chrome against the compiled CSS (RTL and LTR, start and end) instead of adding a one-off harness.

Live previews

Related issues

The off-canvas RTL transform used a `:root:dir(rtl)` ancestor, which is
more specific than `[open] { transform: none }`. In RTL the drawer stayed
translated outside the viewport while the backdrop still appeared.

Wrap the RTL qualifier in `:where()` so it has the same specificity as
the LTR off-canvas rule and the open state can win.

Fixes twbs#43340
@ump45nose
ump45nose requested a review from a team as a code owner November 10, 2026 23:30
@julien-deramond julien-deramond added v6 v6, the main branch bug Something does not work as documented css Sass sources or compiled CSS labels Nov 11, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something does not work as documented css Sass sources or compiled CSS v6 v6, the main branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v6: Drawer is not visible / positioned outside the viewport in RTL mode

2 participants